package main

import (
	"fmt"
)

func main() {
	/*
				Go语言中的指针操作非常简单，只需要记住两个符号：&（取地址）和*（根据地址取值）。
				例如
					a := 10  ptr := &a  此时ptr的类型就是指针类型（*int），指向了变量a的内存地址
					c := *ptr  意思是将ptr指针指向的变量的值获取出来，c为10

		注意：
			var a *int
		    *a = 100
		    会报错。因为如果指针变量一开始没有分配内存空间，就没有办法直接存值，而是只能将这个变量指向一个分配好的内存空间
	*/
	demo1PtrInitGet()

	/*
		方法参数使用指针变量x *T，这样方法内部对于x的更改会传递到方法外部
	*/
	demo2MethodPointerArgs()

	/*
			go中的new和make, 都是用来分配内存空间的函数
				func new(Type) *Type
				func make(t Type, size ...IntegerType) Type

		- new函数分配空间后，返回指向这个类型的指针，默认的值是0值。一般new函数用的少
		- make函数分配空间后，直接返回这个类型本身。make函数用于slice，map，chan类型的内存创建
			b := make(map[string]int, 10)
	*/
	demo3NewMake()
}

func demo1PtrInitGet() {
	a := 10
	b := &a
	fmt.Printf("a:%d ptr:%p\n", a, &a) // a:10 ptr:0xc00001a078
	fmt.Printf("b:%p type:%T\n", b, b) // b:0xc00001a078 type:*int
	fmt.Println(&b)                    // 0xc00000e018

	// 指针取值
	c := *b
	fmt.Println(c) // 10

	// 指针声明时不分配变量，默认为空指针
	var nilPtr *string
	fmt.Println(nilPtr)            // nil
	fmt.Printf("p的值是%v\n", nilPtr) // nil
	if nilPtr == nil {
		fmt.Println("空指针！！")
	}
}

func demo2MethodPointerArgs() {
	x := 10
	modify1(x)
	fmt.Println(x) // 不生效 10
	modify2(&x)
	fmt.Println(x) // 生效 100
}

// 参数不是指针，修改不对外部生效
func modify1(x int) {
	x = 100
}

// 参数是指针，修改对外部生效
func modify2(x *int) {
	*x = 100
}

func demo3NewMake() {
	/*
		new
	*/
	a := new(int) // a是一个指针变量
	b := new(bool)
	var c *int
	c = new(int)
	*c = 10
	fmt.Printf("%T\n", a) // *int
	fmt.Printf("%T\n", b) // *bool
	fmt.Printf("%T\n", c) // *int
	fmt.Println(*a)       // 0
	fmt.Println(*b)       // false
	fmt.Println(*c)       //10

	/*
		make
	*/
	arr := make([]int, 5)
	arr[1] = 19
	fmt.Println(arr) // [0 19 0 0 0]

	myMap := make(map[string]int)
	myMap["key1"] = 14
	myMap["key2"] = 10
	fmt.Println(myMap) //map[key1:14 key2:10]

	myMap2 := make(map[string]int, 1) // 会自己扩容
	myMap2["key1"] = 188
	myMap2["key2"] = 100
	fmt.Println(myMap2)
}
